import {Component, OnInit, Input, Output, EventEmitter, OnChanges, AfterViewInit} from '@angular/core';
import {FormGroup} from '@angular/forms';

import {FormBase} from './form-base';
import {FormControlService} from './form-control.service';
import {NzMessageService} from 'ng-zorro-antd';
import {HttpService} from '@kylin/http';

export type FormAllowMethod = 'post' | 'put';

@Component({
    selector: 'kylin-form',
    templateUrl: './dynamic-form.component.html',
    styleUrls: ['./dynamic-form.component.css'],
    viewProviders: [FormControlService]
})

export class DynamicFormComponent implements OnInit, OnChanges, AfterViewInit {
    @Input() forms: FormBase<any>[] = [];
    @Input() httpPath = '';
    @Input() submitSuccessMsg = '';
    @Input() submitErrorMsg = '';
    @Input() httpAllowMethod: FormAllowMethod = 'post';
    @Input() hasSubmitButton = true;
    @Input() submitButtonText = '提交';

    @Output() formData: EventEmitter<{}> = new EventEmitter<{}>();
    @Output() formSuccessSubmit: EventEmitter<any> = new EventEmitter<any>();

    form: FormGroup;

    constructor(
        private fcs: FormControlService,
        private message: NzMessageService,
        private http: HttpService
    ) {
    }

    ngOnChanges(event) {
        if (event.forms) {
            this.form = this.fcs.toFormGroup(this.forms);
            this.form.valueChanges.subscribe((value) => {
                const data = this.handleFormData(value);
                this.formData.emit(data);
            });
        }
    }


    ngOnInit() {


    }

    ngAfterViewInit() {

    }

    valueChange(event: { value: any }, target: FormBase<any>) {
        if (target['childKey']) {
            const child = this.findTargetForm(target['childKey']);
            this.clearSelectOptions(child);
            this.fcs.fetchSelectOptions(child['fetchData']['path'] + event.value, child['fetchData'])
                .then((res) => {
                    child['options'] = res;
                });
        }
    }

    /**
     *
     * 如果修改了一个级联的下拉,那么所有子级联的options和value都会清空,因为修改了value以后会连续触发valueChange
     */
    private clearSelectOptions(target) {
        target['options'] = [];
        this.form.get(target['key']).setValue('');
    }

    /**
     *
     * @param value
     */
    private handleFormData(value: any) {
        const data = value;
        this.forms.map(i => {
            if (i.controlType === 'location') {

            }
            if (i.controlType === 'select') {

            }
            if (i.controlType === 'upload') {

            }
            if (i.controlType === 'cascader') {

            }
        });
        return data;
    }

    onSubmit = (extraData = {}): Promise<any> => {

        return new Promise((resolve, reject) => {
            let allowSubmit = true;
            const controls = this.form.controls;
            for (const i in controls) {
                if (controls[i].errors) {
                    if (controls[i].errors.required) {
                        const name = this.findFormLabel(i);
                        this.message.error(`${name}为必填项`);
                    } else {
                        const msg = controls[i].errors.key.errorMsg;
                        this.message.error(msg);
                    }
                    allowSubmit = false;
                    return;
                }
            }

            if (!allowSubmit) {
                return reject('');
            }

            const body = this.handleFormData(this.form.value);

            this.http[this.httpAllowMethod](this.httpPath, {...body, ...extraData})
                .then(res => {
                    if (res.status === 200) {
                        this.formSuccessSubmit.emit(res);
                        if (this.submitSuccessMsg) {
                            this.message.success(this.submitSuccessMsg);
                        }
                        resolve(res);
                    } else {
                        if (this.submitErrorMsg) {
                            this.message.error(this.submitErrorMsg);
                        }
                    }

                })
                .catch(err => {
                    if (this.submitErrorMsg) {
                        this.message.error(this.submitErrorMsg);
                    }
                    reject(err);
                });
        });
    };

    reset = () => {
        this.form.reset();
    };

    private findFormLabel(key: string): string {
        let result = '';
        this.forms.map(i => {
            if (i.key === key) {
                result = i.label;
            }
        });
        return result;
    }

    private findTargetForm(key) {
        let target = {};
        this.forms.map(i => {
            if (i.key === key) {
                target = i;
            }
        });
        return target;
    }
}
